
from S3D import Sound, IO
from S3D.Tools.Sound.EventSearcher import Updater

class NameQueryTask:
    def __init__(self, isSubName):
        self.isSubName = isSubName

    @staticmethod
    def makeType(isSubName):
        return lambda: NameQueryTask(isSubName)

    def getAutoParams(self):
        return []

    def getDesc(self):
        return "name", [not self.isSubName and "Name" or "SubName"]

    def setData(self, value):
        self.value = value

    def filter(self, events):
        if not self.value:
            return events

        res = []

        keys = self.value.split(' ')

        for ev in events:
            index  = 0
            offset = 0

            if not self.isSubName:
                if not ev.name.startswith(keys[0]):
                    continue
                index  = 1
                offset = len(keys[0])

            ok = True
            while index < len(keys):
                key = keys[index]
                offset = ev.name.find(key, offset)
                if offset == -1:
                    ok = False
                    break

                offset = offset + len(key)
                index += 1

            if ok: res.append(ev)

        return res

class ParamQueryTask:
    def __init__(self, paramIndex):
        self.paramIndex = paramIndex

    @staticmethod
    def makeType(paramIndex):
        return lambda: ParamQueryTask(paramIndex)

    def getAutoParams(self):
        return [Updater.EVENT_PROP_PARAM + self.paramIndex]

    def getDesc(self):
        try:
            rangeFrom, rangeTo, _ = Updater.DEFAULT_RANGES[self.paramIndex]
        except KeyError:
            rangeFrom, rangeTo = 0, 0

        return "range", [Sound.EVENT_PROPERTIES[self.paramIndex][0], rangeFrom, rangeTo]

    def setData(self, rangeFrom, rangeTo):
        self.rangeFrom = rangeFrom
        self.rangeTo   = rangeTo

    def filter(self, events):
        res = []

        paramIndex = self.paramIndex
        for ev in events:
            value = ev.params[paramIndex]
            if value >= self.rangeFrom and value <= self.rangeTo:
                res.append(ev)

        return res

class LevelsCountQueryTask:
    def getAutoParams(self):
        return [Updater.EVENT_PROP_LEVELS]

    def getDesc(self):
        return "range", ["Levels count", 0, 0]

    def setData(self, rangeFrom, rangeTo):
        self.rangeFrom = rangeFrom
        self.rangeTo   = rangeTo

    def filter(self, events):
        res = []

        for ev in events:
            count = len(ev.levels)
            if count >= self.rangeFrom and count <= self.rangeTo:
                res.append(ev)

        return res

class BankTypeQueryTask:
    def __init__(self, platformIndex):
        self.platformIndex = platformIndex

    @staticmethod
    def makeType(platformIndex):
        return lambda: BankTypeQueryTask(platformIndex)

    def getAutoParams(self):
        return [Updater.EVENT_PROP_SOUNDBANK]

    def getDesc(self):
        return "list", [
            "Bank type on %s" % Sound.SHOW_PLATFORMS[self.platformIndex],
            Updater.SOUNDBANK_TYPE[Updater.SOUNDBANK_TYPE_AUTOLOADING],
            Updater.SOUNDBANK_TYPE
        ]

    def setData(self, selectedTypes):
        res = []
        for type in selectedTypes:
            try:
                res.append(Updater.SOUNDBANK_TYPE.index(type))
            except ValueError:
                pass

        self.selectedTypes = res

    def filter(self, events):
        res = []

        for p in events:
            if p.bankTypes[self.platformIndex] not in self.selectedTypes:
                continue

            res.append(p)

        return res

class LevelNameQueryTask:
    def getAutoParams(self):
        return [Updater.EVENT_PROP_LEVELS]

    def getDesc(self):
        levels = []
        for path in IO.walk(Sound.getLsaPath(), '.lsa', False):
            levels.append(IO.getName(path))

        return "list", ["Level name", "", levels]

    def setData(self, selectedLevels):
        self.selectedLevels = set(selectedLevels)

    def filter(self, events):
        if not self.selectedLevels:
            return events

        return [p for p in events if set(p.levels) & self.selectedLevels]

class BaseSimpleQueryTask:
    def getDesc(self):
        return "simple", [self.getTitle()]

    def getAutoParams(self):
        return []

    def getTitle(self):
        raise NotImplementedError()

    def setData(self):
        pass

    def filter(self, events):
        raise NotImplementedError()

class DuplicateNameQueryTask(BaseSimpleQueryTask):
    def getTitle(self):
        return "Duplicated names"

    def filter(self, events):
        names = {}
        res = []

        for ev in events:
            if ev.name not in names:
                names[ev.name] = ev
                continue

            res.append(ev)

            prev = names[ev.name]
            if prev is not None:
                res.append(prev)
                names[ev.name] = None
                
        return res

class NeverUsedQueryTask(BaseSimpleQueryTask):
    def getAutoParams(self):
        return [Updater.EVENT_PROP_LEVELS]

    def getTitle(self):
        return "Never used"

    def filter(self, events):
        return [p for p in events if not p.levels]

class MultipleBanksQueryTask(BaseSimpleQueryTask):
    def getAutoParams(self):
        return [Updater.EVENT_PROP_SOUNDBANK]

    def getTitle(self):
        return "Multiple banks"

    def filter(self, events):
        return [p for p in events if len(p.banks) > 1]

class InvalidBankTypeQueryTask(BaseSimpleQueryTask):
    def getTitle(self):
        return "Invalid soundbank type"

    def getAutoParams(self):
        return [Updater.EVENT_PROP_SOUNDBANK]

    def filter(self, events):
        res = []
        for ev in events:
            if Updater.SOUNDBANK_TYPE_INVALID in ev.bankTypes:
                res.append(ev)
        return res

TASKS = [
    ("Name/Name",                           NameQueryTask.makeType(False)),
    ("Name/Sub name",                       NameQueryTask.makeType(True)),
    ("Name/Error: Duplicates",              DuplicateNameQueryTask),
    ("Levels/Name",                         LevelNameQueryTask),
    ("Levels/Count",                        LevelsCountQueryTask),
    ("Levels/Error: Never used",            NeverUsedQueryTask),
]

for index, name in enumerate(Sound.SHOW_PLATFORMS):
    TASKS.append(("Soundbanks/Bank type: %s" % name, BankTypeQueryTask.makeType(index)))

TASKS.extend([
    ("Soundbanks/Error: Multiple banks",    MultipleBanksQueryTask),
    ("Soundbanks/Error: Invalid type",      InvalidBankTypeQueryTask),
])

for index, (name, _) in enumerate(Sound.EVENT_PROPERTIES):
    TASKS.append(("Parameter/%s" % name, ParamQueryTask.makeType(index)))